デイリースクラムのファシリテーターをランダムで決めるSlack Botをサーバーレスで作った
私のいるチームでは、毎日10時30分からデイリースクラムをしています。 最近、「ファシリテーターを変えてみよう」という事になりました。 当初はデイリースクラムの最後に「次の人を指名する」という運用を数日していましたが、忘れたり時間切れで決めれない場合がありました。
そこで、ランダムでファシリテーターを決める仕組みを作ってみました。
おすすめの方
- Slack Botを作りたい方(通知動作)
- AWS SAMでAWS Lambdaをデプロイしたい方
Slackアプリの作成と通知先URLの取得
Slackアプリの作成
下記にアクセスして、Slackアプリを作成します。
Incoming Webhooksの設定
Incoming Webhooksを選択し、ON
にします。
ページの下側にある「Add New Webhook to Workspace」を選択し、任意のチャンネルを許可します。
追加完了したあとは、URLをメモしておきます。
AWS Systems ManagerのパラメータストアにSlack通知先を追加
下記コマンドでAWS Systems Managerのパラメータストアに追加します。
URLの先頭にhttps://
があると、AWS CLIコマンド実行に失敗するため除去しています。
aws ssm put-parameter \ --type 'String' \ --name '/Slack/DailyScrumChannelUrl' \ --value 'hooks.slack.com/services/xxxxx/yyyyy/zzzzz'
Slack Botを作成する
sam init
sam init \ --runtime python3.9 \ --name Daily-Scrum-Facilitator-Bot \ --app-template hello-world \ --package-type Zip
SAMテンプレート
通知先のURLは、AWS Systems Managerのパラメータストアから直接取得しています。 また、10時30分からデイリースクラムを開始するので、1分前の10時29分に起動させます。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Daily-Scrum-Facilitator-Bot Parameters: DailyScrumChannelUrl: Type: AWS::SSM::Parameter::Value<String> Default: /Slack/DailyScrumChannelUrl Resources: NotifyDailyScrumFacilitatorFunction: Type: AWS::Serverless::Function Properties: CodeUri: src/ Handler: app.lambda_handler Runtime: python3.9 Timeout: 10 Architectures: - x86_64 Environment: Variables: DAILY_SCRUM_CHANNEL_URL: !Ref DailyScrumChannelUrl Events: Notify: Type: Schedule Properties: Schedule: "cron(29 1 ? * MON-FRI *)" # 月-金の10時29分(JST) NotifyDailyScrumFacilitatorFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/${NotifyDailyScrumFacilitatorFunction}
Lambdaコード
メンションをしたいので、メッセージのtype
をmrkdwn
にしています。plain_text
だとメンションされませんでした。
import json import os import urllib.request import random NOTIFY_SLACK_URL = os.environ['DAILY_SCRUM_CHANNEL_URL'] HIT_USERS_NUMBER = 4 USERS = [ {'userId': 'aaa', 'name': 'Aさん'}, {'userId': 'bbb', 'name': 'Bさん'}, {'userId': 'ccc', 'name': 'Cさん'}, {'userId': 'ddd', 'name': 'Dさん'}, {'userId': 'eee', 'name': 'Eさん'}, {'userId': 'fff', 'name': 'Fさん'}, ] def lambda_handler(event, context): payload = make_payload() post_slack(payload) def make_payload(): hit_users = random.sample(USERS, HIT_USERS_NUMBER) main_user_id = hit_users.pop()['userId'] sub_user_names = '\n'.join([x.get('name') for x in hit_users]) return { 'blocks': [ { 'type': 'section', 'text': { 'type': 'mrkdwn', 'text': f'今日のファシリテーターは、 <@{main_user_id}> です!' } }, { 'type': 'section', 'text': { 'type': 'mrkdwn', 'text': f'不在の場合は、次の人にお任せしましょう。 ```{sub_user_names}```' } } ] } def post_slack(payload): try: res = post(f'https://{NOTIFY_SLACK_URL}', data=payload) except requests.exceptions.RequestException as e: print(e) raise else: print(res.status) def post(url: str, data: dict, headers: dict = {}): req = urllib.request.Request(url, data=json.dumps(data).encode('utf-8'), headers=headers, method='POST') return urllib.request.urlopen(req)
メンバーIDは、Slackのプロフィールで取得できます。
デプロイ
sam package \ --output-template-file packaged.yaml \ --s3-bucket cm-fujii.genki-deploy sam deploy \ --template-file packaged.yaml \ --stack-name daily-scrum-facilitator-bot-stack \ --s3-bucket cm-fujii.genki-deploy \ --capabilities CAPABILITY_NAMED_IAM \ --no-fail-on-empty-changeset
動作確認
朝10時29分になると、無事に通知が来ました!
なお、「開始ギリギリすぎて近況トークの準備に困る」とのフィードバックをもらったので、10時に通知するように変更したいと思います。